package com.example.datachange.utils;

import com.example.datachange.model.Dog;
import org.apache.commons.lang3.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Supplier;

/**
 *
 * @author zhouhao
 * @since  2021/9/30 10:44
 */
public class DateUtils {

    public static String format(Date date, String format, String timezone) {
        if (date == null) {
            return "";
        }
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        if(StringUtils.isNotEmpty(timezone)){
            sdf.setTimeZone(TimeZone.getTimeZone(timezone));
        }
        return sdf.format(date);
    }

    public static String format(Date date, String format) {
        return format(date, format, null);
    }

    public static Date valueOf(String s, String format) {
        return parse(s, format);
    }

    public static Date parse(String s, String format) {
        if (s == null) {
            return null;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        try {
            return sdf.parse(s);
        } catch (ParseException e) {
            return new Date();
        }
    }

    public static Date parse(String s) {
        if (s == null) {
            return null;
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            return sdf.parse(s);
        }
        catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取两个日期间的天数
     * @author Hao.
     * @date 2022/1/6 9:46
     * @param before
     * @param after
     * @return int
     */
    public static int getDistanceOfTwoDate(Date before, Date after) {
        long beforeTime = before.getTime();
        long afterTime = after.getTime();
        return (int) ((afterTime - beforeTime) / (1000 * 60 * 60 * 24));
    }

    /**
     * 获取两个日期间的月数
     * @author Hao.
     * @date 2022/1/6 9:46
     * @param before
     * @param after
     * @return int
     */
    public static int getDistanceMonth(Date before, Date after){
        Calendar bef = Calendar.getInstance();
        Calendar aft = Calendar.getInstance();
        bef.setTime(before);
        aft.setTime(after);
        int result = aft.get(Calendar.MONTH) - bef.get(Calendar.MONTH);
        int month = (aft.get(Calendar.YEAR) - bef.get(Calendar.YEAR)) * 12;
        return Math.abs(month + result);
    }

    /**
     * 【start】-【end】时间段的数据统计填充【data】
     * @author Hao.
     * @date 2022/1/6 10:21
     * @param oldList 时间段内查询出的数据
     * @param start 起始时间
     * @param end 结束时间
     * @param dateField 数据统计的时间字段名
     * @param data 填充数据的方法
     * @return 填充的数据
     */
    public static <T> List<T> addDayForData(List<T> oldList, Date start, Date end, String dateField, Supplier<? extends T> data) throws Exception {
        long n = DateUtils.getDistanceOfTwoDate(start, end);
        LinkedList<T> newList = new LinkedList<>();
        int num = oldList.size();
        int temp = 0;
        for (int i = 0; i < n; i++) {
            String dateFieldToUpperCase = dateField.substring(0, 1).toUpperCase() + dateField.substring(1);
            if (temp < num) {
                Date currentDate = (Date) oldList.get(temp).getClass().getMethod("get" + dateFieldToUpperCase).invoke(oldList.get(temp));
                // 开始日期小于当前记录日期 增加自定义数据
                if (start.compareTo(currentDate) < 0) {
                    newList.add(data.get());
                    newList.getLast().getClass().getMethod("set" + dateFieldToUpperCase, Date.class).invoke(newList.getLast(), start);
                }
                // 原数据加入
                if (start.compareTo(currentDate) == 0) {
                    newList.add(oldList.get(temp));
                    temp++;
                }
            } else if (start.compareTo(end) <= 0) {
                // 增加自定义数据
                newList.add(data.get());
                newList.getLast().getClass().getMethod("set" + dateFieldToUpperCase, Date.class).invoke(newList.getLast(), start);
            }
            //开始时间向前加一天
            start = addDateOneDay(start);
        }
        return newList;
    }

    public static Date addDateOneDay(Date date) {
        if (null == date) {
            return date;
        }
        Calendar c = Calendar.getInstance();
        c.setTime(date);   //设置当前日期
        c.add(Calendar.DATE, 1); //日期加1天
//     c.add(Calendar.DATE, -1); //日期减1天
        date = c.getTime();
        return date;
    }

    /**
     *
     * getBetweenDates(查询两个器之间的日期(格式yyyy-MM-dd),包括起讫日期)
     *
     * @param start
     * @param end
     * @return
     * List<String>
     * @exception
     * @since  1.0.0
     */
    public static List<String> getBetweenDatesString(Date start, Date end) {
        List<String> result = new ArrayList<String>();
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
        result.add(sdf.format(start));
        Calendar tempStart = Calendar.getInstance();
        tempStart.setTime(start);
        tempStart.add(Calendar.DAY_OF_YEAR, 1);

        Calendar tempEnd = Calendar.getInstance();
        tempEnd.setTime(end);

        while (tempStart.before(tempEnd)||tempStart.equals(tempEnd)) {
            result.add(sdf.format(tempStart.getTime()));
            tempStart.add(Calendar.DAY_OF_YEAR, 1);
        }
        //result.add(sdf.format(end));
        return result;
    }

    public static void main(String[] args) throws Exception {
        Date start = DateUtils.parse("2021-12-11", "yyyy-MM-dd");
        Date end = DateUtils.parse("2022-01-11", "yyyy-MM-dd");
        int distanceOfTwoDate = DateUtils.getDistanceOfTwoDate(start, end);
        List<Dog> list = new ArrayList<>();
        list.add(new Dog("小黄", DateUtils.parse("2021-12-11", "yyyy-MM-dd")));
        list.add(new Dog("大黄", DateUtils.parse("2021-12-12", "yyyy-MM-dd")));
        list.add(new Dog("小绿", DateUtils.parse("2021-12-13", "yyyy-MM-dd")));
        list.add(new Dog("大绿", DateUtils.parse("2021-12-16", "yyyy-MM-dd")));
        list.add(new Dog("小明", DateUtils.parse("2022-01-11", "yyyy-MM-dd")));
        System.out.println(distanceOfTwoDate);
        List<String> betweenDatesString = getBetweenDatesString(start, end);
        List<Dog> dogs = addDayForData(list, start, end, "birthday", Dog::new);
        System.out.println(dogs);
    }
}
